using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using ShellLib;

[assembly: System.Reflection.AssemblyKeyFile(@"..\..\KeyFile.snk")]

namespace ThunderMain.Shell {	

	/// <summary>
	/// Column Handler for all files - adds an MD5 hash of the file as a new column
	/// 
	/// Needs to be registered with RegAsm.exe and installed in the gac with GacUtil.exe
	/// </summary>
	[Guid("D389C53B-F038-47d8-9E85-32D966B37657"), ComVisible(true)]
	public class MD5ColumnHandler : ColumnProvider {
		const int S_OK=0;
		const int S_FALSE=1;

		public MD5ColumnHandler() {
		}

		public override int Initialize(LPCSHCOLUMNINIT psci) {
			return S_OK;
		}
		public override int GetColumnInfo(int dwIndex, out SHCOLUMNINFO psci) {			
			psci=new SHCOLUMNINFO();
			
			if(dwIndex!=0) 
				return S_FALSE;

			try {
				psci.scid.fmtid=GetType().GUID;			
				psci.scid.pid=0;

				// Cast to a ushort, because a VARTYPE is ushort and a VARENUM is int
				psci.vt=(ushort)VarEnum.VT_BSTR;
				psci.fmt=LVCFMT.LEFT;
				psci.cChars=40;

				psci.csFlags=SHCOLSTATE.TYPE_STR;

				psci.wszTitle = "MD5 Hash";
				psci.wszDescription = "Provides an MD5 Hash of every file";
			} catch(Exception e) {
				MessageBox.Show(e.Message);
				return S_FALSE;
			}

			return S_OK;
		}
		public override int GetItemData( LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, out object pvarData) {
			pvarData=string.Empty;

			// Ignore directories
			if(((FileAttributes)pscd.dwFileAttributes|FileAttributes.Directory)==FileAttributes.Directory)
				return S_FALSE;
			
			// Only service known columns
			if(pscid.fmtid!=GetType().GUID || pscid.pid!=0)
				return S_FALSE;
			
			try {	
				MD5 md5 = new MD5CryptoServiceProvider();
				byte[] result; 

				using(Stream stream=File.OpenRead(pscd.wszFile)) {
					result = md5.ComputeHash(stream);
				}

				StringBuilder output=new StringBuilder(2+(result.Length*2));

				foreach(byte b in result) {
					output.Append(b.ToString("x2"));
				}
				pvarData="0x" + output.ToString();

			} catch(UnauthorizedAccessException) {
				return S_FALSE;
			}catch(Exception e) {
				MessageBox.Show(e.Message);
				return S_FALSE;
			}

			return S_OK;
		}


	}
}
